﻿namespace QuickMail.BusinessLogic
{
    using System;
    using System.ComponentModel;
    using System.Windows.Forms;
    using HigLabo.Net.Imap;
    using HigLabo.Net.Pop3;
    using HigLabo.Net.Smtp;
    using QuickMail.Properties;


    public class TestConnectionController
    {
        #region Fields

        public delegate void TestConnectionHandler(bool incomingResult, bool outgoingResult);
        public event TestConnectionHandler TestConnectionComplete;

        public bool IncomingTestResult;
        public bool OutgoingTestResult;

        private readonly Timer ConnecTimer = new Timer { Interval = 10000 };
        private BackgroundWorker ConnectBgw = new BackgroundWorker { WorkerSupportsCancellation = true };

        #endregion //Fields

        /// <summary>
        /// Checks the connections settings to the mail.
        /// </summary>
        public bool CheckConnectSettings()
        {
            if (string.IsNullOrEmpty(Settings.Default.GetEmail)
                || string.IsNullOrEmpty(Settings.Default.GetServer)
                || Settings.Default.GetPort == 0
                || string.IsNullOrEmpty(Settings.Default.SendEmail)
                || string.IsNullOrEmpty(Settings.Default.SendServer)
                || Settings.Default.SendPort == 0)
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// Runs thread of test connection.
        /// </summary>
        public void RunTestConntection()
        {
            ConnectBgw.DoWork += ConnectBgwOnDoWork;
            ConnectBgw.RunWorkerCompleted += ConnectBgwOnRunWorkerCompleted;

            if (!ConnectBgw.IsBusy)
                ConnectBgw.RunWorkerAsync();
            else
            {
                ConnectBgw.Dispose();
                ConnectBgw = new BackgroundWorker { WorkerSupportsCancellation = true };
                ConnectBgw.RunWorkerAsync();
            }

            ConnecTimer.Tick += ConnecTimerOnTick;
            ConnecTimer.Start();
        }

        /// <summary>
        /// Performs test connection by 2nd thread.
        /// </summary>
        private void ConnectBgwOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
        {
            if (Settings.Default.GetServerType == 0)
            {
                using (var imapClient = new ImapClient(Settings.Default.GetServer)
                {
                    Port = Settings.Default.GetPort,
                    UserName = Settings.Default.GetEmail,
                    Password = CryptWorker.Decrypt(Settings.Default.GetPassword),
                    Ssl = Settings.Default.GetUseSsl
                })
                {
                    IncomingTestResult = TestConnectionWorker.ImapTestConnection(imapClient);
                }
            }
            else
            {
                using (var pop3Client = new Pop3Client(Settings.Default.GetServer)
                {
                    Port = Settings.Default.GetPort,
                    UserName = Settings.Default.GetEmail,
                    Password = CryptWorker.Decrypt(Settings.Default.GetPassword),
                    Ssl = Settings.Default.GetUseSsl
                })
                {
                    IncomingTestResult = TestConnectionWorker.Pop3TestConnection(pop3Client);
                }
            }

            using (var smtpClient = new SmtpClient(Settings.Default.SendServer)
            {
                AuthenticateMode = HelpWorker.GetAuthenticateMode(),
                EncryptedCommunication = HelpWorker.GetCryptType(),
                Port = Settings.Default.SendPort,
                UserName = Settings.Default.SendEmail,
                Password = CryptWorker.Decrypt(Settings.Default.SendPassword)
            })
            {
                OutgoingTestResult = TestConnectionWorker.SmtpTestConnection(smtpClient);
            }
        }

        /// <summary>
        /// Unsubscribes from the events at the end of test.
        /// </summary>
        private void ConnectBgwOnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs runWorkerCompletedEventArgs)
        {
            ConnectBgw.DoWork -= ConnectBgwOnDoWork;
            ConnectBgw.RunWorkerCompleted -= ConnectBgwOnRunWorkerCompleted;

            ConnecTimer.Tick -= ConnecTimerOnTick;
            ConnecTimer.Stop();

            if (TestConnectionComplete != null)
                TestConnectionComplete(IncomingTestResult, OutgoingTestResult);

        }

        /// <summary>
        /// Terminates execution of the test, if has timed out.
        /// </summary>
        private void ConnecTimerOnTick(object sender, EventArgs eventArgs)
        {
            ConnectBgw.CancelAsync();

            ConnectBgw.DoWork -= ConnectBgwOnDoWork;
            ConnectBgw.RunWorkerCompleted -= ConnectBgwOnRunWorkerCompleted;

            ConnecTimer.Tick -= ConnecTimerOnTick;
            ConnecTimer.Stop();

            if (TestConnectionComplete != null)
                TestConnectionComplete(IncomingTestResult, OutgoingTestResult);
        }
    }
}
